/**
 * RopesView
 * 
 * @param config
 * @returns
 */
function RopesView(config) {
	this.page = config.page;
	this.fireButton = config.fireButton;
	this.playButton = config.playButton;
	this.resetButton = config.resetButton;
	this.helpButton = config.helpButton;
	this.jqTimer = config.jqTimer;
	this.ropes = config.ropes;

	this.fire = false;
	this.time = 0;
	this.helpState = false;
}

RopesView.prototype.init = function(controller) {
	this.controller = controller;
	var _this = this;
	this.chronoClock = new ChronoClock(this.jqTimer.get(0).getContext("2d"));

	this.fireButton.click(function() {
		if (!_this.helpState && !_this.fireButton.hasClass('button-disabled')) {
			_this.setFireState(true);
		}

		return _this.helpState;
	});

	this.page.click(this.createPageClickHandler());

	this.playing = false;
	this.timer = new Timer(function(time) {
		_this.updateTime(time);
	}, 0.12, 50);
	this.playButton.click(function() {
		_this.setPlayState(!_this.playing);
	});

	this.resetButton.click(function() {
		_this.reset();
	});

	this.helpButton.click(function() {
		var helpShowed = false;
		if (!_this.helpState) {
			helpShowed = true;
			_this.showHelp();
		}

		return !helpShowed;
	});
};

RopesView.prototype.createPageClickHandler = function(ropeIndex, jqRope) {
	var _this = this;
	return function(event) {
		for ( var i = 0; i < _this.ropes.length; i++) {
			var rope = _this.ropes[i];
			var offset = rope.jqRope.offset();
			var tolerance = 10;

			var width = rope.jqRope.width();
			var xInBounds = (event.pageX >= offset.left - tolerance)
					&& (event.pageX <= offset.left + width + tolerance);

			var height = rope.jqRope.height();
			var yInBounds = (event.pageY >= offset.top - tolerance) && (event.pageY <= offset.top + height + tolerance);

			if (xInBounds && yInBounds) {
				var ropeY = event.pageY - offset.top;
				_this.onRopeClick(i, rope.jqRope, ropeY);
			}
		}

		_this.setFireState(false);
	};
};

RopesView.prototype.onRopeClick = function(ropeIndex, jqRope, y) {
	if (this.fire) {
		var extremity = (y > jqRope.height() / 2) ? 'bottom' : 'top';
		this.controller.onSetFire(ropeIndex, extremity);
	}
};

RopesView.prototype.setFireState = function(fireState) {
	this.fire = fireState;
	if (this.fire) {
		this.page.addClass('fire-cursor');
		this.fireButton.addClass('border-red');
	} else {
		this.page.removeClass('fire-cursor');
		this.fireButton.removeClass('border-red');
	}
};

RopesView.prototype.setPlayState = function(playing) {
	if (!playing) {
		this.playButton.removeClass('button-pause');
		this.playButton.addClass('button-play');
		this.timer.pause();
	} else {
		this.timer.play();
		this.playButton.removeClass('button-play');
		this.playButton.addClass('button-pause');
	}
	this.playing = playing;
};

RopesView.prototype.reset = function() {
	this.timer.stop();
	this.updateTime(0);
	this.controller.reset();
	for ( var i = 0; i < this.ropes.length; i++) {
		this.ropes[i].jqTop.hide();
		this.ropes[i].jqBottom.hide();
	}
	this.setPlayState(false);
	this.helpState = false;
};

RopesView.prototype.showHelp = function() {
	if (this.time == 0) {
		this.helpState = true;
		this.setFireState(false);
		this.updateChrono(47, 45);

		var ropesState = [ {
			top : 1,
			bottom : 0,
			nofire : true
		}, {
			top : 1,
			bottom : 0,
			nofire : true
		} ];

		this.updateRopes(ropesState);

		var self = this;
		this.page.one('click', function() {
			self.reset();
		});
	}
};

RopesView.prototype.updateTime = function(time) {
	this.time = time;
	if (this.time > 60) {
		this.timer.stop();
	}

	if (this.time > 0) {
		this.helpButton.addClass('button-disabled');
	} else {
		this.helpButton.removeClass('button-disabled');
	}

	this.controller.updateTime(time);
};

RopesView.prototype.update = function(ropesState) {
	this.updateChrono();
	this.updateRopes(ropesState);
	this.updateFireButton(ropesState);
};

RopesView.prototype.updateChrono = function(time, marker) {
	var chronoTime = time || this.time;
	this.chronoClock.updateTime(chronoTime, marker);
};

RopesView.prototype.updateRopes = function(ropesState) {
	for ( var i = 0; i < this.ropes.length; i++) {
		this.updateRope(this.ropes[i], ropesState[i]);
	}
};

RopesView.prototype.updateRope = function(rope, ropeState) {
	if (ropeState.top + ropeState.bottom <= 1) {
		var topHeight = rope.jqTop.height();
		var top = Math.max(-topHeight, ropeState.top) * rope.jqRope.height() - topHeight;
		rope.jqTop.css('top', top);
		rope.jqAshTop.css('height', top + 10);

		var bottom = Math.max(-topHeight, ropeState.bottom) * rope.jqRope.height();
		rope.jqBottom.css('bottom', bottom);
		rope.jqAshBottom.css('height', bottom);
	}

	if (ropeState.top === 0) {
		rope.jqTop.show();
	}
	if (ropeState.nofire) {
		rope.jqTop.hide();
	}

	if (ropeState.bottom === 0) {
		rope.jqBottom.show();
	}
	if (ropeState.nofire) {
		rope.jqBottom.hide();
	}
};

RopesView.prototype.updateFireButton = function(ropesState) {
	var fireEnabled = (this.time === 0);

	for ( var i = 0; i < ropesState.length; i++) {
		var burned = ropesState[i].burned;

		if (burned) {
			fireEnabled = true;
			break;
		}
	}

	if (!fireEnabled) {
		this.fireButton.addClass('button-disabled');
	} else {
		this.fireButton.removeClass('button-disabled');
	}
};

RopesView.prototype.onSolved = function() {
	this.timer.stop();
	alert('Solved');
};

RopesView.prototype.onStale = function(overTime) {
	this.timer.stop();
	this.updateChrono(60, this.time);

	var reason = (overTime) ? 'too late!' : 'too early!';
	alert('Failed: ' + reason);
};

/**
 * Timer
 * 
 * @param callback
 * @param increment
 * @param intervall
 * @returns
 */
function Timer(callback, increment, intervall) {
	this.callback = callback;
	this.time = 0;
	this.timerId = null;
	this.interval = intervall;
	this.increment = increment;
}

Timer.prototype.play = function() {
	if (this.timerId == null) {
		var _this = this;
		this.callback(this.time);
		this.timerId = setInterval(function() {
			_this.time += _this.increment;
			_this.callback(_this.time);
		}, _this.interval);
	}
};

Timer.prototype.pause = function() {
	this.clearIntervall();
};

Timer.prototype.stop = function() {
	this.clearIntervall();
	this.time = 0;
};

Timer.prototype.clearIntervall = function() {
	if (this.timerId != null) {
		clearInterval(this.timerId);
		this.timerId = null;
	}
};

/**
 * Chrono clock
 * 
 * @returns
 */
function ChronoClock(canvasContext) {
	this.context = canvasContext;
	this.width = this.context.canvas.width;
	this.height = this.context.canvas.height;
}

ChronoClock.prototype.updateTime = function(chronoTime, marker) {
	var centerX = 30;
	var centerY = 30;
	var outerRadius = 28;
	var innerRadius = 24;
	var context = this.context;

	function clearScreen() {
		context.clearRect(0, 0, this.width, this.height);
	}

	function drawBackground() {
		context.beginPath();
		context.arc(centerX, centerY, outerRadius, 0, 2 * Math.PI, false);
		context.fillStyle = 'white';
		context.fill();
		context.lineWidth = 4;
		context.strokeStyle = '#666';
		context.stroke();
	}

	function drawForeground() {
		var dAngle = -Math.PI / 2;

		function drawArc(angle, color) {
			context.beginPath();
			context.moveTo(centerX, centerY);
			context.arc(centerX, centerY, innerRadius, dAngle, angle + dAngle, false);
			context.moveTo(centerX, centerY);
			context.closePath();
			context.fillStyle = color;
			context.fill();
		}

		var angle = chronoTime / 60 * 2 * Math.PI;
		var angleGrey = Math.min(Math.PI * 11 / 8, angle);
		var angleGren = Math.min(Math.PI * 25 / 16, angle);

		drawArc(angle, 'red');
		drawArc(angleGren, 'green');
		drawArc(angleGrey, 'grey');
	}

	function drawMarker() {
		context.beginPath();
		context.moveTo(centerX, centerY);

		var angle = marker / 60 * 2 * Math.PI - Math.PI / 2;
		var x = Math.cos(angle) * innerRadius + centerX;
		var y = Math.sin(angle) * innerRadius + centerY;

		context.lineTo(x, y);
		context.strokeStyle = '#000';
		context.lineWidth = 1;
		context.stroke();
	}

	clearScreen.call(this);
	drawBackground.call(this);
	drawForeground.call(this);

	if (marker) {
		drawMarker.call(this);
	}
};
